package redora.performance.runners;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
import java.util.Random;

import net.sf.json.JSONObject;
import org.hibernate.Session;
import redora.exceptions.RedoraException;
import redora.performance.PerformanceTest;
import redora.performance.test.hibernate.model.Tweet;
import redora.performance.test.hibernate.util.HibernateUtil;

/**
 * Runs the benchmark for Hibernate persistence.
 */
public class HibernateRunner {

    public static void main(String[] args) throws RedoraException, IOException {
        run(1000);
    }

    public static long[] run(int count) throws RedoraException, IOException {
        long[] ret = { 99999999999999L, 99999999999999999L, 9999999999999999L, 9999999999999999L,
                9999999999999999L, 9999999999999999L };

        PerformanceTest.prepare();

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        ret[0] = insert(session, count);
        session.clear();

        ret[1] = retrieve(session);
        session.clear();

        ret[2] = perObject(session, count);
        session.clear();

        ret[3] = update(session);
        session.clear();

        long[] json = json(session);
        ret[4] = json[0];
        ret[5] = json[1];
        session.clear();

        return ret;
    }

    private static long insert(Session session, int count) {
        long start = System.nanoTime();

        for (int i = 0; i < count; i++) {
            Tweet p = new Tweet();
            p.setSmallText("text" + i);
            p.setNumber(new Random(i).nextInt());
            p.setCreationDate(new Date());
            session.save(p);
        }
        return Math.abs(System.nanoTime() - start);
    }

    @SuppressWarnings("unchecked")
    private static long retrieve(Session session) {
        long start = System.nanoTime();
        List<Tweet> all = session.createQuery("from Tweet").list();
        for (Tweet p : all)
            if (!p.getSmallText().equals("nomatch"))
                p.getNumber();

        return Math.abs(System.nanoTime() - start);
    }

    private static long perObject(Session session, int count) {
        insert(session, count);
        long start = System.nanoTime();
        for (int i = 1; i < count; i++) {
            Tweet p = new Tweet();
            session.load(p, (long) i);
            p.getCreationDate();
        }
        return Math.abs(System.nanoTime() - start);
    }

    @SuppressWarnings("unchecked")
    private static long update(Session session) {
        List<Tweet> all = session.createQuery("from Tweet").list();
        long start = System.nanoTime();
        for (Tweet p : all) {
            if (!p.getSmallText().equals("nomatch")) {
                p.setNumber(new Random().nextInt());
                p.setSmallText("text");
                p.setUpdateDate(new Date());
                session.update(p);
            }
        }
        session.flush();
        return Math.abs(System.nanoTime() - start);
    }

    @SuppressWarnings("unchecked")
    private static long[] json(Session session) throws IOException {
        long[] retval = { 999999999999L, 99999999999999L };
        File tmp = File.createTempFile("jsonHibernate", ".tmp");
        PrintWriter out = new PrintWriter(tmp);
        //ObjectMapper mapper = new ObjectMapper();
        long start = System.nanoTime();
        List<Tweet> list = session.createQuery("from Tweet").list();
        out.write('[');
        for (Tweet p : list) {
            // mapper.writeValue(out, p);
            out.write(JSONObject.fromObject(p).toString());
            out.write(',');
        }
        out.write(']');
        out.close();
        retval[0] = Math.abs(System.nanoTime() - start);
        retval[1] = tmp.length();

        tmp.delete();

        return retval;
    }
}
